home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / imap / non-ANSI / ipopd / ipop2d.c next >
C/C++ Source or Header  |  1997-02-25  |  15KB  |  582 lines

  1. /*
  2.  * Program:    IPOP2D - IMAP2 to POP2 conversion server
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    28 October 1990
  13.  * Last Edited:    25 February 1997
  14.  *
  15.  * Copyright 1997 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made
  24.  * available "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35.  
  36.  
  37. /* Parameter files */
  38.  
  39. #include "mail.h"
  40. #include "osdep.h"
  41. #include <stdio.h>
  42. #include <ctype.h>
  43. #include <netdb.h>
  44. #include <errno.h>
  45. extern int errno;        /* just in case */
  46. #include <signal.h>
  47. #include <pwd.h>
  48. #include "misc.h"
  49.  
  50.  
  51. /* Autologout timer */
  52. #define TIMEOUT 60*30
  53.  
  54.  
  55. /* Size of temporary buffers */
  56. #define TMPLEN 1024
  57.  
  58.  
  59. /* Server states */
  60.  
  61. #define LISN 0
  62. #define AUTH 1
  63. #define MBOX 2
  64. #define ITEM 3
  65. #define NEXT 4
  66. #define DONE 5
  67.  
  68. /* Global storage */
  69.  
  70. char *version = "2.3(17)";    /* server version */
  71. short state = LISN;        /* server state */
  72. MAILSTREAM *stream = NIL;    /* mailbox stream */
  73. long nmsgs = 0;            /* number of messages */
  74. long current = 1;        /* current message number */
  75. long size = 0;            /* size of current message */
  76. char status[MAILTMPLEN];    /* space for status string */
  77. char *user = "";        /* user name */
  78. char *pass = "";        /* password */
  79. short *msg = NIL;        /* message translation vector */
  80.  
  81.  
  82. /* Function prototypes */
  83.  
  84. void main  ();
  85. void clkint  ();
  86. void kodint  ();
  87. short c_helo  ();
  88. short c_fold  ();
  89. short c_read  ();
  90. short c_retr  ();
  91. short c_acks  ();
  92. short c_ackd  ();
  93. short c_nack  ();
  94.  
  95. /* Main program */
  96.  
  97. void main (argc,argv)
  98.     int argc;
  99.     char *argv[];
  100. {
  101.   char *s,*t;
  102.   struct hostent *hst;
  103.   char cmdbuf[TMPLEN];
  104. #include "linkage.c"
  105.   openlog ("ipop2d",LOG_PID,LOG_MAIL);
  106.   gethostname (status,TMPLEN-1);/* get local name */
  107.   s = cpystr ((hst = gethostbyname (status)) ? hst->h_name : status);
  108.   rfc822_date (cmdbuf);        /* get date/time now */
  109.   printf ("+ %s POP2 %s w/IMAP2 client %s at %s\015\012",s,version,
  110.       "(Comments to MRC@CAC.Washington.EDU)",cmdbuf);
  111.   fflush (stdout);        /* dump output buffer */
  112.   signal (SIGALRM,clkint);    /* prepare for clock interrupt */
  113.   signal (SIGUSR2,kodint);    /* prepare for Kiss Of Death */
  114.   state = AUTH;            /* initial server state */
  115.   while (state != DONE) {    /* command processing loop */
  116.     alarm (TIMEOUT);        /* get a command under timeout */
  117.     while (!fgets (cmdbuf,TMPLEN-1,stdin)) {
  118.       if (errno==EINTR) errno=0;/* ignore if some interrupt */
  119.       else {
  120.     syslog (LOG_INFO,"Connection broken while reading line from %.80s",
  121.         tcp_clienthost (cmdbuf));
  122.     _exit (1);
  123.       }
  124.     }
  125.     alarm (0);            /* make sure timeout disabled */
  126.                 /* find end of line */
  127.     if (!strchr (cmdbuf,'\012')) {
  128.       puts ("- Command line too long\015");
  129.       state = DONE;
  130.     }
  131.     else if (!(s = strtok (cmdbuf," \015\012"))) {
  132.       puts ("- Missing or null command\015");
  133.       state = DONE;
  134.     }
  135.     else {            /* dispatch based on command */
  136.       ucase (s);        /* canonicalize case */
  137.                 /* snarf argument */
  138.       t = strtok (NIL,"\015\012");
  139.       if ((state == AUTH) && !strcmp (s,"HELO")) state = c_helo (t,argc,argv);
  140.       else if ((state == MBOX || state == ITEM) && !strcmp (s,"FOLD"))
  141.     state = c_fold (t);
  142.       else if ((state == MBOX || state == ITEM) && !strcmp (s,"READ"))
  143.     state = c_read (t);
  144.       else if ((state == ITEM) && !strcmp (s,"RETR")) state = c_retr (t);
  145.       else if ((state == NEXT) && !strcmp (s,"ACKS")) state = c_acks (t);
  146.       else if ((state == NEXT) && !strcmp (s,"ACKD")) state = c_ackd (t);
  147.       else if ((state == NEXT) && !strcmp (s,"NACK")) state = c_nack (t);
  148.       else if ((state == AUTH || state == MBOX || state == ITEM) &&
  149.            !strcmp (s,"QUIT")) {
  150.     if (t) puts ("- Bogus argument given to QUIT\015");
  151.     else {            /* valid sayonara */
  152.                 /* expunge the stream */
  153.       if (stream && nmsgs) mail_expunge (stream);
  154.       puts ("+ Sayonara\015");/* acknowledge the command */
  155.     }
  156.     state = DONE;        /* done in either case */
  157.       }
  158.       else {            /* some other or inappropriate command */
  159.     printf ("- Bogus or out of sequence command - %s\015\012",s);
  160.     state = DONE;
  161.       }
  162.     }
  163.     fflush (stdout);        /* make sure output blatted */
  164.   }
  165.   mail_close (stream);        /* clean up the stream */
  166.   syslog (LOG_INFO,"Logout from %.80s",tcp_clienthost (cmdbuf));
  167.   exit (0);            /* all done */
  168. }
  169.  
  170. /* Clock interrupt
  171.  */
  172.  
  173. void clkint ()
  174. {
  175.   char tmp[MAILTMPLEN];
  176.   puts ("- Autologout; idle for too long\015");
  177.   syslog (LOG_INFO,"Autologout user=%.80s host=%.80s",user ? user : "???",
  178.       tcp_clienthost (tmp));
  179.   fflush (stdout);        /* make sure output blatted */
  180.   mail_close (stream);        /* try to gracefully close the stream */
  181.   stream = NIL;
  182.   exit (0);            /* die die die */
  183. }
  184.  
  185.  
  186. /* Kiss Of Death interrupt
  187.  */
  188.  
  189. void kodint ()
  190. {
  191.   char tmp[MAILTMPLEN];
  192.   puts ("- Received Kiss of Death\015");
  193.   syslog (LOG_INFO,"Kiss of death user=%.80s host=%.80s",user ? user : "???",
  194.       tcp_clienthost (tmp));
  195.   fflush (stdout);        /* make sure output blatted */
  196.   mail_close (stream);        /* try to gracefully close the stream */
  197.   stream = NIL;
  198.   exit (0);            /* die die die */
  199. }
  200.  
  201. /* Parse HELO command
  202.  * Accepts: pointer to command argument
  203.  * Returns: new state
  204.  */
  205.  
  206. short c_helo (t,argc,argv)
  207.     char *t;
  208.     int argc;
  209.     char *argv[];
  210. {
  211.   unsigned long i;
  212.   char *s,*u,*p;
  213.   char tmp[TMPLEN];
  214.   struct passwd *pwd = getpwnam ("nobody");
  215.   if (!(t && *t && (u = strtok (t," ")) && (p = strtok (NIL,"\015\012")))) {
  216.     puts ("- Missing user or password\015");
  217.     return DONE;
  218.   }
  219.                 /* copy password, handle quoting */
  220.   for (s = tmp; *p; p++) *s++ = (*p == '\\') ? *++p : *p;
  221.   *s = '\0';            /* tie off string */
  222.   pass = cpystr (tmp);
  223.   if (s = strchr (u,':')) {    /* want remote mailbox? */
  224.     *s++ = '\0';        /* separate host name from user name */
  225.     user = cpystr (s);        /* note user name */
  226.     syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%s",u,user,
  227.         tcp_clienthost (tmp));
  228.     sprintf (tmp,"{%s}INBOX",u);/* initially remote INBOX */
  229.     if (pwd) {            /* try to become someone harmless */
  230.       setgid (pwd->pw_gid);    /* set group ID */
  231.       setuid (pwd->pw_uid);    /* and user ID */
  232.     }
  233.   }
  234.   else if (((i = strlen (u)) < 64) &&
  235.        server_login (user = cpystr (u),pass,NIL,argc,argv)) {
  236.     syslog (LOG_INFO,"Login user=%.80s host=%.80s",user,tcp_clienthost (tmp));
  237.     strcpy (tmp,"INBOX");    /* local; attempt login, select INBOX */
  238.   }
  239.   else {
  240.     if (i > 128) syslog (LOG_ALERT|LOG_AUTH,"Crack attempt, host=%.80s",
  241.              tcp_clienthost (tmp));
  242.     sleep (3);            /* slow the cracker down */
  243.     puts ("- Bad login\015");
  244.     syslog (LOG_INFO,"Login failure user=%.80s host=%.80s",user,
  245.         tcp_clienthost(tmp));
  246.     return DONE;
  247.   }
  248.   return c_fold (tmp);        /* open default mailbox */
  249. }
  250.  
  251. /* Parse FOLD command
  252.  * Accepts: pointer to command argument
  253.  * Returns: new state
  254.  */
  255.  
  256. short c_fold (t)
  257.     char *t;
  258. {
  259.   long i,j;
  260.   char *s,tmp[TMPLEN];
  261.   if (!(t && *t)) {        /* make sure there's an argument */
  262.     puts ("- Missing mailbox name\015");
  263.     return DONE;
  264.   }
  265.                 /* expunge old stream */
  266.   if (stream && nmsgs) mail_expunge (stream);
  267.   nmsgs = 0;            /* no more messages */
  268.   if (msg) fs_give ((void **) &msg);
  269.                 /* don't permit proxy to leave IMAP */
  270.   if (stream && stream->mailbox && (s = strchr (stream->mailbox,'}'))) {
  271.     strncpy (tmp,stream->mailbox,i = (++s - stream->mailbox));
  272.     strcpy (tmp+i,t);        /* append mailbox to initial spec */
  273.     t = tmp;
  274.   }
  275.                 /* open mailbox, note # of messages */
  276.   if (j = (stream = mail_open (stream,t,NIL)) ? stream->nmsgs : 0) {
  277.     sprintf (tmp,"1:%d",j);    /* fetch fast information for all messages */
  278.     mail_fetchfast (stream,tmp);
  279.     msg = (short *) fs_get ((stream->nmsgs + 1) * sizeof (short));
  280.     for (i = 1; i <= j; i++)    /* find undeleted messages, add to vector */
  281.       if (!mail_elt (stream,i)->deleted) msg[++nmsgs] = i;
  282.   }
  283.   printf ("#%d messages in %s\015\012",nmsgs,stream ? stream->mailbox :
  284.       "<none>");
  285.   return MBOX;
  286. }
  287.  
  288. /* Parse READ command
  289.  * Accepts: pointer to command argument
  290.  * Returns: new state
  291.  */
  292.  
  293. short c_read (t)
  294.     char *t;
  295. {
  296.   MESSAGECACHE *elt = NIL;
  297.   if (t && *t) {        /* have a message number argument? */
  298.     current = atoi (t);        /* set message number if possible */
  299.                 /* validity check message number */
  300.     if (current < 1 || current > nmsgs) {
  301.       puts ("- Invalid message number given to READ\015");
  302.       return DONE;
  303.     }
  304.   }
  305.   else if (current > nmsgs) {    /* at end of mailbox? */
  306.     puts ("=0 No more messages\015");
  307.     return MBOX;
  308.   }
  309.                 /* set size if message valid and exists */
  310.   size = msg[current] ? (elt = mail_elt(stream,msg[current]))->rfc822_size : 0;
  311.   if (elt) sprintf (status,"Status: %s%s\015\012",
  312.             elt->seen ? "R" : " ",elt->recent ? " " : "O");
  313.   else status[0] = '\0';    /* no status */
  314.   size += strlen (status);    /* update size to reflect status */
  315.                 /* display results */
  316.   printf ("=%d characters in message %d\015\012",size,current);
  317.   return ITEM;
  318. }
  319.  
  320.  
  321. /* Parse RETR command
  322.  * Accepts: pointer to command argument
  323.  * Returns: new state
  324.  */
  325.  
  326. short c_retr (t)
  327.     char *t;
  328. {
  329.   char c,*s;
  330.   if (t) {            /* disallow argument */
  331.     puts ("- Bogus argument given to RETR\015");
  332.     return DONE;
  333.   }
  334.   if (size) {            /* message size valid? */
  335.     fputs (status,stdout);    /* yes, output message */
  336.     fputs (mail_fetchheader (stream,msg[current]),stdout);
  337.     fputs (mail_fetchtext (stream,msg[current]),stdout);
  338.   }
  339.   else return DONE;        /* otherwise go away */
  340.   return NEXT;
  341. }
  342.  
  343. /* Parse ACKS command
  344.  * Accepts: pointer to command argument
  345.  * Returns: new state
  346.  */
  347.  
  348. short c_acks (t)
  349.     char *t;
  350. {
  351.   char tmp[TMPLEN];
  352.   if (t) {            /* disallow argument */
  353.     puts ("- Bogus argument given to ACKS\015");
  354.     return DONE;
  355.   }
  356.                 /* mark message as seen */
  357.   sprintf (tmp,"%d",msg[current++]);
  358.   mail_setflag (stream,tmp,"\\Seen");
  359.   return c_read (NIL);        /* end message reading transaction */
  360. }
  361.  
  362.  
  363. /* Parse ACKD command
  364.  * Accepts: pointer to command argument
  365.  * Returns: new state
  366.  */
  367.  
  368. short c_ackd (t)
  369.     char *t;
  370. {
  371.   char tmp[TMPLEN];
  372.   if (t) {            /* disallow argument */
  373.     puts ("- Bogus argument given to ACKD\015");
  374.     return DONE;
  375.   }
  376.                 /* mark message as seen and deleted */
  377.   sprintf (tmp,"%d",msg[current]);
  378.   mail_setflag (stream,tmp,"\\Seen \\Deleted");
  379.   msg[current++] = 0;        /* mark message as deleted */
  380.   return c_read (NIL);        /* end message reading transaction */
  381. }
  382.  
  383.  
  384. /* Parse NACK command
  385.  * Accepts: pointer to command argument
  386.  * Returns: new state
  387.  */
  388.  
  389. short c_nack (t)
  390.     char *t;
  391. {
  392.   if (t) {            /* disallow argument */
  393.     puts ("- Bogus argument given to NACK\015");
  394.     return DONE;
  395.   }
  396.   return c_read (NIL);        /* end message reading transaction */
  397. }
  398.  
  399. /* Co-routines from MAIL library */
  400.  
  401.  
  402. /* Message matches a search
  403.  * Accepts: MAIL stream
  404.  *        message number
  405.  */
  406.  
  407. void mm_searched (stream,msgno)
  408.     MAILSTREAM *stream;
  409.     long msgno;
  410. {
  411.   /* Never called */
  412. }
  413.  
  414.  
  415. /* Message exists (mailbox)
  416.     i.e. there are that many messages in the mailbox;
  417.  * Accepts: MAIL stream
  418.  *        message number
  419.  */
  420.  
  421. void mm_exists (stream,number)
  422.     MAILSTREAM *stream;
  423.     long number;
  424. {
  425.   /* Can't use this mechanism.  POP has no means of notifying the client of
  426.      new mail during the session. */
  427. }
  428.  
  429.  
  430. /* Message expunged
  431.  * Accepts: MAIL stream
  432.  *        message number
  433.  */
  434.  
  435. void mm_expunged (stream,number)
  436.     MAILSTREAM *stream;
  437.     long number;
  438. {
  439.   /* This isn't used */
  440. }
  441.  
  442.  
  443. /* Message status changed
  444.  * Accepts: MAIL stream
  445.  *        message number
  446.  */
  447.  
  448. void mm_flags (stream,number)
  449.     MAILSTREAM *stream;
  450.     long number;
  451. {
  452.   /* This isn't used */
  453. }
  454.  
  455.  
  456. /* Mailbox found
  457.  * Accepts: Mailbox name
  458.  */
  459.  
  460. void mm_mailbox (string)
  461.     char *string;
  462. {
  463.   /* This isn't used */
  464. }
  465.  
  466.  
  467. /* BBoard found
  468.  * Accepts: BBoard name
  469.  */
  470.  
  471. void mm_bboard (string)
  472.     char *string;
  473. {
  474.   /* This isn't used */
  475. }
  476.  
  477. /* Notification event
  478.  * Accepts: MAIL stream
  479.  *        string to log
  480.  *        error flag
  481.  */
  482.  
  483. void mm_notify (stream,string,errflg)
  484.     MAILSTREAM *stream;
  485.     char *string;
  486.     long errflg;
  487. {
  488.   mm_log (string,errflg);    /* just do mm_log action */
  489. }
  490.  
  491.  
  492. /* Log an event for the user to see
  493.  * Accepts: string to log
  494.  *        error flag
  495.  */
  496.  
  497. void mm_log (string,errflg)
  498.     char *string;
  499.     long errflg;
  500. {
  501.   /* Not doing anything here for now */
  502. }
  503.  
  504.  
  505. /* Log an event to debugging telemetry
  506.  * Accepts: string to log
  507.  */
  508.  
  509. void mm_dlog (string)
  510.     char *string;
  511. {
  512.   /* Not doing anything here for now */
  513. }
  514.  
  515.  
  516. /* Get user name and password for this host
  517.  * Accepts: host name
  518.  *        where to return user name
  519.  *        where to return password
  520.  *        trial count
  521.  */
  522.  
  523. void mm_login (host,username,password,trial)
  524.     char *host;
  525.     char *username;
  526.     char *password;
  527.     long trial;
  528. {
  529.   strcpy (username,user);    /* set user name */
  530.   strcpy (password,pass);    /* and password */
  531. }
  532.  
  533. /* About to enter critical code
  534.  * Accepts: stream
  535.  */
  536.  
  537. void mm_critical (stream)
  538.     MAILSTREAM *stream;
  539. {
  540.   /* Not doing anything here for now */
  541. }
  542.  
  543.  
  544. /* About to exit critical code
  545.  * Accepts: stream
  546.  */
  547.  
  548. void mm_nocritical (stream)
  549.     MAILSTREAM *stream;
  550. {
  551.   /* Not doing anything here for now */
  552. }
  553.  
  554.  
  555. /* Disk error found
  556.  * Accepts: stream
  557.  *        system error code
  558.  *        flag indicating that mailbox may be clobbered
  559.  * Returns: abort flag
  560.  */
  561.  
  562. long mm_diskerror (stream,errcode,serious)
  563.     MAILSTREAM *stream;
  564.     long errcode;
  565.     long serious;
  566. {
  567.   syslog (LOG_ALERT,"Retrying after disk error %.80s",strerror (errcode));
  568.   sleep (5);            /* can't do much better than this! */
  569.   return NIL;
  570. }
  571.  
  572.  
  573. /* Log a fatal error event
  574.  * Accepts: string to log
  575.  */
  576.  
  577. void mm_fatal (string)
  578.     char *string;
  579. {
  580.   mm_log (string,ERROR);    /* shouldn't happen normally */
  581. }
  582.